using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Generic;
using MonoMac.Foundation;
using System.Drawing;

namespace SpyTouchClient
{
	public class ViewBasicInfo
	{
		public long ViewHandle { get; set; }
		public NSNumber ViewHandleNumber { get; set; }
		public long SuperViewHandle { get; set; }
		public string TypeName { get; set; }
		public bool Hidden { get; set; }
		public RectangleF Frame { get; set; }

		public ViewBasicInfo ()
		{
			TypeName = "";
		}

		public void Set (string serial)
		{
			var parts = serial.Split (' ');
			TypeName = parts[0];
			ViewHandle = long.Parse (parts[1]);
			ViewHandleNumber = new NSNumber(ViewHandle);
			SuperViewHandle = long.Parse (parts[2]);
			Hidden = bool.Parse (parts[3]);
			var rparts = parts[4].Split (',');
			Frame = new RectangleF (float.Parse (rparts[0]), float.Parse (rparts[1]), float.Parse (rparts[2]), float.Parse (rparts[3]));
		}

		public override string ToString ()
		{
			return string.Format ("[ViewBasicInfo: ViewHandle={0}, SuperViewHandle={1}, TypeName={2}, Hidden={3}, Frame={4}]", ViewHandle, SuperViewHandle, TypeName, Hidden, Frame);
		}
	}

	public class Server
	{
		StreamReader _reader;
		StreamWriter _writer;

		Action<string> _log;

		public Server (Action<string> log)
		{
			_log = log;
			var th = new Thread (Run);
			th.Start ();
		}

		void Run ()
		{
			var listener = new TcpListener (IPAddress.Any, 20001);
			listener.Start ();
			_log ("Waiting for connection");
			for (;;) {
				try {
					using (var socket = listener.AcceptSocket ()) {
						_log ("Connected");
						using (var stream = new NetworkStream (socket)) {
							_reader = new StreamReader (stream);
							_writer = new StreamWriter (stream);
							
							RunClient ();
						}
					}
				} catch (Exception ex) {
					_log (ex.Message);
				}
				_writer = null;
				_reader = null;
			}
		}

		public void GetVisualTree (Action<List<ViewBasicInfo>> k)
		{
			ExecuteCommand ("GetVisualTree", res =>
			{
				var list = new List<ViewBasicInfo> ();
				
				var lines = res.Split ('\n');
				
				foreach (var l in lines) {
					var t = l.Trim ();
					if (t.Length > 0) {
						var vb = new ViewBasicInfo ();
						vb.Set (t);
						list.Add (vb);
					}
				}
				
				k (list);
			});
		}

		AutoResetEvent _newCmd;
		string _cmd;
		Action<string> _resp;

		void ExecuteCommand (string cmd, Action<string> resp)
		{
			if (_writer == null || _reader == null || _newCmd == null) {
				resp ("");
				return;
			}
			
			_cmd = cmd;
			_resp = resp;
			_newCmd.Set ();
		}

		void RunClient ()
		{
			_newCmd = new AutoResetEvent (false);
			for (;;) {
				_newCmd.WaitOne ();
				_writer.WriteLine (_cmd);
				_writer.Flush ();
				_resp (Uri.UnescapeDataString (_reader.ReadLine () ?? ""));
			}
		}
	}
}

